package com.sluggard.security.manage.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sluggard.security.manage.mapper.MenuMapper;
import com.sluggard.security.manage.model.entity.MenuEntity;
import com.sluggard.security.manage.model.res.MenuInfoRes;
import com.sluggard.security.manage.model.res.MenuRes;
import com.sluggard.security.manage.model.res.RouteRes;
import com.sluggard.security.manage.service.IMenuService;
import com.sluggard.security.manage.service.IRoleMenuService;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 菜单管理 服务实现类
 * </p>
 *
 * @author lizheng
 * @since 2024-04-28
 */
@Service
public class MenuServiceImpl extends ServiceImpl<MenuMapper, MenuEntity> implements IMenuService {

    @Resource
    private IRoleMenuService roleMenuService;

    @Override
    public List<MenuEntity> tree(QueryWrapper<MenuEntity> queryWrapper) {
        return parseMenuNode(baseMapper.getAllMenuNode(queryWrapper));
    }

    @Override
    public MenuInfoRes loadMenuInfo(Long roleId) {
        List<Long> menuIds = roleMenuService.selectByRoleId(roleId);
        if(menuIds.isEmpty()){
            return new MenuInfoRes();
        }
        QueryWrapper<MenuEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("id", menuIds);
        queryWrapper.eq("status", Boolean.TRUE);
        queryWrapper.eq("deleted", 0);
        List<MenuEntity> allMenuNode = baseMapper.getAllMenuNode(queryWrapper);
        List<MenuEntity> menuNodeRes = parseMenuNode(allMenuNode);

        // 装配路由
        List<RouteRes> routeRes = loadRoute(menuNodeRes);

        // 装配菜单 过滤按钮
        List<MenuRes> menus = loadMenu(menuNodeRes.stream()
                .filter(item -> 2 != item.getType())
                .collect(Collectors.toList()));

        // 装配按钮
        Set<String> buttons = allMenuNode.parallelStream().filter(item -> 2 == item.getType())
                .map(MenuEntity::getCode)
                .collect(Collectors.toSet());

        return new MenuInfoRes(buttons, menus, routeRes);
    }

    @Override
    public List<MenuRes> tree() {
        QueryWrapper<MenuEntity> queryWrapper = new QueryWrapper<MenuEntity>()
                .eq("status", Boolean.TRUE);
        return loadMenu(parseMenuNode(baseMapper.getAllMenuNode(queryWrapper)));
    }

    @Override
    public void onDelete(List<Long> ids) {
        Iterator<Long> iterator = ids.iterator();
        while (iterator.hasNext()){
            Long next = iterator.next();
            List<MenuEntity> menuEntities = baseMapper.selectByParentId(next);
            if(!menuEntities.isEmpty()){
                iterator.remove();
            }
        }
    }

    private List<MenuRes> loadMenu(List<MenuEntity> menuNodeRes) {
        return menuNodeRes.parallelStream()
                .map(item -> {
                    MenuRes menuRes = new MenuRes();
                    menuRes.setKey(item.getId().toString());
                    menuRes.setName(item.getTitle());
                    menuRes.setType(item.getType());
                    menuRes.setActiveMenu(item.getActiveMenu());
                    menuRes.setIcon(item.getIcon());
                    menuRes.setPath(item.getPath());
                    if (StringUtils.isNoneBlank(item.getRedirectUrl())) {
                        menuRes.setPath(item.getRedirectUrl());
                    }
                    if (!CollectionUtils.isEmpty(item.getChildren())) {
                        menuRes.setChildren(loadMenu(item.getChildren()));
                    }
                    return menuRes;
                }).collect(Collectors.toList());
    }

    private List<RouteRes> loadRoute(List<MenuEntity> menuNodeRes) {
        return menuNodeRes.parallelStream()
                .map(item -> {
                    RouteRes routeRes = new RouteRes();
                    routeRes.put("key", item.getId().toString());
                    routeRes.setName(item.getTitle());
                    routeRes.setPath(item.getPath());
                    routeRes.setRedirectUrl(item.getRedirectUrl());
                    routeRes.setComponent(item.getComponent());
                    if (!CollectionUtils.isEmpty(item.getChildren())) {
                        routeRes.setChildren(loadRoute(item.getChildren()));
                    }
                    return routeRes;
                }).collect(Collectors.toList());
    }

    private List<MenuEntity> parseMenuNode(List<MenuEntity> nodes) {
        List<MenuEntity> result = new ArrayList<>();

        Map<Long, MenuEntity> dtoMap = new HashMap<>();
        for (MenuEntity menu : nodes) {
            dtoMap.put(menu.getId(), menu);
        }
        for (Map.Entry<Long, MenuEntity> entry : dtoMap.entrySet()) {
            MenuEntity node = entry.getValue();
            if (node.getParentId() == null || node.getParentId() == 0) {
                result.add(node);
            } else {
                if (dtoMap.get(node.getParentId()) != null) {
                    dtoMap.get(node.getParentId()).addChild(node);
                    dtoMap.get(node.getParentId()).getChildren().sort(Comparator.comparingInt(MenuEntity::getSortNo));
                }
            }
        }
        nodes.clear();
        dtoMap.clear();
        result.sort(Comparator.comparingInt(MenuEntity::getSortNo));
        return result;
    }
}
